#include <iostream>
#include "core/Game.h"
#ifdef SOKO3D_USE_GLFW
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#endif
#include "render/Renderer.h"
#include "render/Camera.h"
#include "app/LevelLoader.h"
#ifdef SOKO3D_USE_IMGUI
#include <imgui.h>
#include <backends/imgui_impl_glfw.h>
#include <backends/imgui_impl_opengl3.h>
#include <vector>
#include <string>
#include <cstdio>
#endif

int main() {
    std::vector<std::string> levelPaths = enumerateLevelFiles("assets/levels");
    size_t currentIndex = 0;
    Level lvl = levelPaths.empty() ? Level::fromStringGrid(std::vector<std::string>{"#####","#.@ #","# $*#","#   #","#####"}) : loadLevelFromFile(levelPaths[currentIndex]);
    Game game(lvl);
    std::cout << "Sokoban3D" << std::endl;
#ifdef SOKO3D_USE_GLFW
    if (!glfwInit()) return -1;
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
    glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
    GLFWwindow* window = glfwCreateWindow(800, 600, "Sokoban3D", nullptr, nullptr);
    if (!window) { glfwTerminate(); return -1; }
    glfwMakeContextCurrent(window);
    glfwSwapInterval(1);
    if (!gladLoadGL()) { glfwDestroyWindow(window); glfwTerminate(); return -1; }

    Renderer renderer;
    renderer.init("assets/shaders/basic.vert","assets/shaders/basic.frag");
    Camera cam;
    cam.setTarget({(float)game.level().width()*0.5f,(float)0.5f,(float)game.level().height()*0.5f});
    cam.setDistance(std::max(game.level().width(), game.level().height())*1.5f);

    int totalSteps = 0;
    int lastSteps = 0;
    bool pendingSwitch = false;
    double switchTimer = 0.0;
    double lastTime = glfwGetTime();
    struct AppCtx { Game* game; Camera* cam; std::vector<std::string>* paths; size_t* index; int* total; int* last; } ctx{ &game, &cam, &levelPaths, &currentIndex, &totalSteps, &lastSteps };
    glfwSetWindowUserPointer(window, &ctx);
    glfwSetKeyCallback(window, [](GLFWwindow* w,int key,int sc,int action,int mods){
        if(action!=GLFW_PRESS) return;
        auto* c = static_cast<AppCtx*>(glfwGetWindowUserPointer(w));
        if(!c) return;
        if(key==GLFW_KEY_ESCAPE) { glfwSetWindowShouldClose(w,1); return; }
        if(key==GLFW_KEY_R) { c->game->reset(); return; }
        if(key==GLFW_KEY_U) { c->game->undo(); return; }
        if(key==GLFW_KEY_LEFT || key==GLFW_KEY_A) { c->game->move(Direction::Left); return; }
        if(key==GLFW_KEY_RIGHT || key==GLFW_KEY_D) { c->game->move(Direction::Right); return; }
        if(key==GLFW_KEY_UP || key==GLFW_KEY_W) { c->game->move(Direction::Up); return; }
        if(key==GLFW_KEY_DOWN || key==GLFW_KEY_S) { c->game->move(Direction::Down); return; }
        if(key==GLFW_KEY_L) {
            size_t next = *c->index + 1;
            if(next < c->paths->size()){
                *c->index = next;
                Level nlvl = loadLevelFromFile((*c->paths)[*c->index]);
                *c->game = Game(nlvl);
                *(c->last) = c->game->stepCount();
                c->cam->setTarget({(float)c->game->level().width()*0.5f,(float)0.5f,(float)c->game->level().height()*0.5f});
                c->cam->setDistance(std::max(c->game->level().width(), c->game->level().height())*1.5f);
            } else {
                *c->index = 0;
                Level nlvl = loadLevelFromFile((*c->paths)[*c->index]);
                *c->game = Game(nlvl);
                *(c->total) = 0;
                *(c->last) = c->game->stepCount();
                c->cam->setTarget({(float)c->game->level().width()*0.5f,(float)0.5f,(float)c->game->level().height()*0.5f});
                c->cam->setDistance(std::max(c->game->level().width(), c->game->level().height())*1.5f);
            }
            return;
        }
    });
    

#ifdef SOKO3D_USE_IMGUI
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGui::StyleColorsDark();
    ImGuiIO& io = ImGui::GetIO();
    const ImWchar* ranges = io.Fonts->GetGlyphRangesChineseSimplifiedCommon();
    ImFont* font = nullptr;
    std::vector<std::string> candidates = {
        "assets/fonts/NotoSansSC-Regular.ttf",
        "assets/fonts/NotoSansSC-Regular.otf",
        "C:/Windows/Fonts/simhei.ttf",
        "C:/Windows/Fonts/SIMHEI.TTF",
        "C:/Windows/Fonts/msyh.ttf",
        "C:/Windows/Fonts/MSYH.TTF"
    };
    for (const auto& p : candidates) {
        font = io.Fonts->AddFontFromFileTTF(p.c_str(), 18.0f, nullptr, ranges);
        if (font) break;
    }
    if (!font) io.Fonts->AddFontDefault();
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init("#version 330");
#endif

    while (!glfwWindowShouldClose(window)) {
        double now = glfwGetTime();
        double dt = now - lastTime; lastTime = now;
        glfwPollEvents();
        int w,h; glfwGetFramebufferSize(window,&w,&h);
        // 累计总步数
        totalSteps += (game.stepCount() - lastSteps);
        lastSteps = game.stepCount();
        // 完成关卡：非最后一关延时自动切换；最后一关停留
        if (game.completed()) {
            size_t next = currentIndex + 1;
            if (next < levelPaths.size()) {
                pendingSwitch = true;
                switchTimer += dt;
                if (switchTimer >= 0.8) {
                    switchTimer = 0.0; pendingSwitch = false;
                    currentIndex = next;
                    Level nlvl = loadLevelFromFile(levelPaths[currentIndex]);
                    game = Game(nlvl);
                    lastSteps = game.stepCount();
                    cam.setTarget({(float)game.level().width()*0.5f,(float)0.5f,(float)game.level().height()*0.5f});
                    cam.setDistance(std::max(game.level().width(), game.level().height())*1.5f);
                }
            }
        } else { pendingSwitch = false; switchTimer = 0.0; }
        renderer.draw(game,cam,w,h);
#ifdef SOKO3D_USE_IMGUI
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
        ImGui::Begin("状态");
        if(!levelPaths.empty()) ImGui::Text("关卡: %s (%d/%d)", levelPaths[currentIndex].c_str(), (int)(currentIndex+1), (int)levelPaths.size());
        ImGui::Text("本关步数: %d", game.stepCount());
        ImGui::Text("总步数: %d", totalSteps);
        ImGui::Text("尺寸: %dx%d", game.level().width(), game.level().height());
        bool win = game.completed();
        if (win && currentIndex+1<levelPaths.size()) {
            if (pendingSwitch) ImGui::TextColored(ImVec4(0.2f,0.8f,0.3f,1.0f), "本关完成! 即将切换到下一关...");
        }
        if (win && currentIndex+1>=levelPaths.size()) { ImGui::TextColored(ImVec4(0.2f,0.8f,0.3f,1.0f), "全部关卡完成! 总步数: %d 致谢：作者 曾子愚", totalSteps); ImGui::Text("按 L 回到第一关并清空步数"); }
        ImGui::Text("WASD/方向键 移动, U 撤销, R 重置, L 下一关");
        if (!font) {
            ImGui::Separator();
            ImGui::TextColored(ImVec4(0.9f,0.7f,0.2f,1.0f), "中文字体未加载，复制字体到 assets/fonts 以消除乱码");
        }
        ImGui::End();
        
        ImGui::Render();
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
#endif
        glfwPollEvents();
        glfwSwapBuffers(window);
    }
#ifdef SOKO3D_USE_IMGUI
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();
#endif
    glfwDestroyWindow(window);
    glfwTerminate();
#endif
    return 0;
}